#include "ArmyState.h"
#include "UserAPI.h"
#include "BasicAI.h"
#include "params.h"

using namespace ArmyStateNS;

std::list<std::pair<GeneralType, Position> > ManageState::managing_map;

bool ManageState::get_manager_offer(Position &center)
{
	BasicAI *ai = BasicAI::instance();
	UserAPI &api = ai->get_api();

	refresh_managing_state();
	if (managing_map.size() >= 2) 
	{
		LOG << "managing_map.size() >= 2" << endl;
		for (managing_map_t::iterator it = managing_map.begin(); it != managing_map.end(); ++it)
		{
			LOG << it->first << " is managing " << toString(it->second) << endl;
		}
		return false;
	}

	int best_score = 0;
	LandCity *best_city = NULL;

	for (int i = 0; i < (int) api.all_cities.size(); ++i)
	{
		LandCity *city = api.all_cities[i];
		Position center = api.GetCityCenter(city);
		if (city->owner != api.get_my_id()) continue;
		if (api.InDanger(center)) continue;
		bool managed = false;
		for (managing_map_t::iterator it = managing_map.begin(); it != managing_map.end(); ++it)
			if (it->second == center)
				managed = true;

		if (!managed)
		{
			int score = city->hasBarrack * 3000 + city->HP * 5 + 100;
			if (score > best_score)
			{
				best_score = score;
				best_city = city;
			}
		}
	}

	if (best_city)
	{
		center = api.GetCityCenter(best_city);
		return true;
	} else
	{
		LOG << "best_city == NULL" << endl;
		return false;
	}
}

void ManageState::assign_manager(Position center, GeneralType name)
{
	for (managing_map_t::iterator it = managing_map.begin(); it != managing_map.end(); ++it)
		if (it->first == name)
		{
			remove_manager(it->first);
			break;
		}

	managing_map.push_back(make_pair(name, center));
}

void ManageState::refresh_managing_state()
{
	BasicAI *ai = BasicAI::instance();
	UserAPI &api = ai->get_api();
	std::set<GeneralType> live_set;
	for (int i = 0; i < (int) api.my_army.size(); ++i)
	{
		GeneralType name = api.my_army[i]->general->type;
		if (ai->get_army_state(name)->get_type() == "ManageState")
			live_set.insert(name);
	}

	for (managing_map_t::iterator it = managing_map.begin(); it != managing_map.end(); )
	{
		if (live_set.find(it->first) == live_set.end())
			it = managing_map.erase(it);
		else
			++it;
	}
}

void ManageState::remove_manager(GeneralType name)
{
	for (managing_map_t::iterator it = managing_map.begin(); it != managing_map.end(); ++it)
		if (it->first == name)
		{
			managing_map.erase(it);
			return;
		}

	LOG << "ManageState::remove_manager failed" << endl;
}


void ManageState::execute()
{
	BasicAI *ai = BasicAI::instance();
	UserAPI &api = ai->get_api();
	if (!(m_target == Position(-1, -1)))
		if (!api.GetCity(m_target) || api.GetCity(m_target)->owner != api.get_my_id())
			m_target = Position(-1, -1);

	Army *army = api.GetMyArmy(m_name);

	if (m_target == Position(-1, -1))
	{
		remove_manager(m_name);

		if (!ManageState::get_manager_offer(m_target))
		{
			ManageState::remove_manager(m_name);
			enter_state(m_name, this, new OffensiveBattleState(m_name));
			return;
		}
	}

	assign_manager(m_target, m_name);

	//if (api.InDanger(army->pos))
	//{
	//	if (api.GetCity(army->pos) == api.GetCity(m_target) || api.HamDistance(army->pos, m_target) <= 7)
	//	{
	//		enter_state(m_name, this, new DefensiveBattleState(m_name, m_target));
	//		return;
	//	} else
	//	{
	//		switch (api.GetMyArmy(m_name)->soldierType) {
	//		case (SOLDIER_INFANTRY):
	//			//	TODO	complete transition
	//			enter_state(m_name, this, new IdleState(m_name));
	//			return;
	//		case (SOLDIER_RANGER):
	//			//	TODO	complete transition
	//			enter_state(m_name, this, new IdleState(m_name));
	//			return;
	//		case (SOLDIER_CAVALRY):
	//			//	TODO	complete transition
	//			enter_state(m_name, this, new IdleState(m_name));
	//			return;
	//		}
	//	}

	//	return;
	//}

	if (api.InDanger(m_target))
	{
		ManageState::remove_manager(m_name);
		enter_state(m_name, this, new DefensiveBattleState(m_name, m_target));
		return;
	}

	//if (api.GetCity(army->pos) != api.GetCity(m_target))
	if (!(army->pos == m_target))
		//	try to move to the city
		api.Move(ai->get_action_queue(), army->pos, m_target);

	LandCity* city = api.GetCity(m_target);
	LOG_ASSERT(city, "can't get city at m_target");
	if (city != NULL) {
		if (city->HP < params::get<int>("HP_LIMIT", 300)) api.RepairCity(ai->get_action_queue(), city);
		if (city->HP > params::get<int>("BARRACK_HP_LIMIT", 50) && !city->hasBarrack) api.BuildBarrack(ai->get_action_queue(), city);

		if (city->hasBarrack)
		{
			int recruit_amount = army->numSoldier < 1000 ? city->totalSoldier : params::get<int>("DEFENSIVE_RECRUIT_AMOUNT", 50);
			api.Recruit(ai->get_action_queue(), recruit_amount);
		}
	}
}
